package uk.co.revisual.domino.proxies
{
	import flexunit.framework.Assert;
	
	import org.puremvc.as3.multicore.interfaces.IProxy;
	
	import uk.co.revisual.domino.core.FSMModel;
	import uk.co.revisual.domino.consts.DominoConsts;
	import uk.co.revisual.domino.errors.StateModelError;
	
	public class FSMModelProxyTest
	{		
		private var data:XML = 				<fsm 	initial="testState001"
													xmlns:t1="namespace.test1" 
													xmlns:t2="namespace.test2">		
			
												<state name="testState001">
													<transition action = "action001" target = "targetState001"/>
													<transition action = "action002" target = "targetState002"/>
													<transition action = "action003" target = "targetState003"/>
													<entering.guard class = "EnteredStartingCmd"/>
													<entered class = "EnteredStartingCmd"/>
													<exiting.guard class = "EnteredStartingCmd"/>	
													<tear.down class = "EnteredStartingCmd"/>
													<cancelled class = "CancelledStartingCmd"/>
												</state>
			
												<state name="testState002">
												</state>
			
												<state name="testState003">
													<entered class = "no.namespace.test1.EnteredCmd"/>
													<tear.down class = "no.namespace.test1.TearDownCmd"/>
													<entering.guard class = "no.namespace.test1.EnteringGuardCmd"/>
													<exiting.guard class = "no.namespace.test1.ExitingGuardCmd"/>
													<cancelled class = "no.namespace.test1.CancelledCmd"/>
												</state>
												<state name="testState004">
													<entered t1:class = "EnteredCmd"/>
													<tear.down t1:class = "TearDownCmd"/>
													<entering.guard t1:class = "EnteringGuardCmd"/>
													<exiting.guard t2:class = "ExitingGuardCmd"/>
													<cancelled t2:class = "CancelledCmd"/>
												</state>
												<state name="testState005">
													<entered />
													<cancelled t1:class = "EnteredCmd" t2:class = "EnteredCmd"/>
												</state>
			
											</fsm>;
				
		[Test]
		public function testSetData():void
		{
			var testSubject:FSMModel = new FSMModelProxy( null );
			var statename:String = "testState001";
			
			try{
				var enteringPath:String = testSubject.getCommandPath( statename, DominoConsts.EVENT_NODES_NAMES.ENTERING_GUARD );
				Assert.fail( "no error thrown for null data" );
			}catch(error:StateModelError){
				Assert.assertEquals( error.id, 5000 + StateModelError.NULL_DATA );
			}catch(error:Error){
				Assert.fail( "unknown error :: " + error.toString() );
			}
			
			IProxy(testSubject).setData( data.copy() );
			var parsedData:XML = XML( IProxy( testSubject ).getData() );
			Assert.assertEquals(parsedData.state[0].@changed.toString(),DominoConsts.INTERNAL.CHANGED);
			Assert.assertEquals(parsedData.state[0].@entering.toString(),DominoConsts.EVENT_NODES_NAMES.ENTERING_GUARD);
			Assert.assertEquals(parsedData.state[0].@exiting.toString(),DominoConsts.EVENT_NODES_NAMES.EXITING_GUARD);
			Assert.assertEquals(parsedData.state[1].@changed.toString(),DominoConsts.INTERNAL.CHANGED);
			Assert.assertEquals( parsedData.state[1].@entering.toString(), "");
			Assert.assertEquals( parsedData.state[1].@exiting.toString(), "");
		}
			
		[Test]
		public function testGetCommandPath():void
		{
			var statename003:String = "testState003";
			var statename004:String = "testState004";
			var statename005:String = "testState005";
			
			var testSubject:FSMModel = new FSMModelProxy( data.copy() );
			Assert.assertEquals( testSubject.getCommandPath( statename003, DominoConsts.EVENT_NODES_NAMES.ENTERED ), "no.namespace.test1.EnteredCmd" );
			Assert.assertEquals( testSubject.getCommandPath( statename003, DominoConsts.EVENT_NODES_NAMES.TEAR_DOWN ), "no.namespace.test1.TearDownCmd" );
			Assert.assertEquals( testSubject.getCommandPath( statename003, DominoConsts.EVENT_NODES_NAMES.ENTERING_GUARD ), "no.namespace.test1.EnteringGuardCmd" );
			Assert.assertEquals( testSubject.getCommandPath( statename003, DominoConsts.EVENT_NODES_NAMES.EXITING_GUARD ), "no.namespace.test1.ExitingGuardCmd" );
			Assert.assertEquals( testSubject.getCommandPath( statename003, DominoConsts.EVENT_NODES_NAMES.CANCELLED ), "no.namespace.test1.CancelledCmd" );
			
			Assert.assertEquals( testSubject.getCommandPath( statename004, DominoConsts.EVENT_NODES_NAMES.ENTERED ), "namespace.test1.EnteredCmd" );
			Assert.assertEquals( testSubject.getCommandPath( statename004, DominoConsts.EVENT_NODES_NAMES.TEAR_DOWN ), "namespace.test1.TearDownCmd" );
			Assert.assertEquals( testSubject.getCommandPath( statename004, DominoConsts.EVENT_NODES_NAMES.ENTERING_GUARD ), "namespace.test1.EnteringGuardCmd" );
			Assert.assertEquals( testSubject.getCommandPath( statename004, DominoConsts.EVENT_NODES_NAMES.EXITING_GUARD ), "namespace.test2.ExitingGuardCmd" );
			Assert.assertEquals( testSubject.getCommandPath( statename004, DominoConsts.EVENT_NODES_NAMES.CANCELLED ), "namespace.test2.CancelledCmd" );
			
			var nodename001:String = DominoConsts.EVENT_NODES_NAMES.ENTERED;
			try{
				var enteringPath:String = testSubject.getCommandPath( statename005, nodename001 );
				Assert.fail( "no error thrown for no class attribute" );
			}catch(error:StateModelError){
				Assert.assertEquals( error.statename, statename005 );
				Assert.assertEquals( error.nodename, nodename001 );
				Assert.assertEquals( error.id, 5000 + StateModelError.NO_CLASS_ATTRIBUTE );
			}catch(error:Error){
				Assert.fail( "unknown error :: " + error.toString() );
			}
			
			var nodename002:String = DominoConsts.EVENT_NODES_NAMES.CANCELLED;
			try{
				enteringPath = testSubject.getCommandPath( statename005, nodename002 );
				Assert.fail( "no error thrown for multiplae class attributes" );
			}catch(error:StateModelError){
				Assert.assertEquals( error.statename, statename005 );
				Assert.assertEquals( error.nodename, nodename002 );
				Assert.assertEquals( error.id, 5000 + StateModelError.MULTIPLE_CLASS_ATTRIBUTES );
			}catch(error:Error){
				Assert.fail( "unknown error :: " + error.toString() );
			}
			
			try{
				enteringPath = testSubject.getCommandPath( null, nodename001 );
				Assert.fail( "no error thrown for null state passed" );
			}catch(error:StateModelError){
				Assert.assertEquals( error.id, 5000 + StateModelError.NULL_STATENAME_PASSED );
			}catch(error:Error){
				Assert.fail( "unknown error :: " + error.toString() );
			}
			
			try{
				enteringPath = testSubject.getCommandPath( statename003, null );
				Assert.fail( "no error thrown for null notename passed" );
			}catch(error:StateModelError){
				Assert.assertEquals( error.id, 5000 + StateModelError.NULL_NOTENAME_PASSED );
			}catch(error:Error){
				Assert.fail( "unknown error :: " + error.toString() );
			}
		}
		
		[Test]
		public function testGetConnectingAction():void
		{
			var testSubject:FSMModel = new FSMModelProxy( data.copy() );
			Assert.assertEquals( testSubject.getConnectingAction("testState001","targetState002"), "action002" );
			Assert.assertNull( testSubject.getConnectingAction("testState003","testState004") );
		}
		
		[Test]
		public function testGetOutgoingActionsForState():void
		{
			var statename001:String = "testState001";
			var statename002:String = "testState002";
			var testSubject:FSMModel = new FSMModelProxy( data.copy() );
			
			var actions:Array = testSubject.getOutgoingActionsForState( statename001 );
			Assert.assertEquals( actions.length, 3 );
			Assert.assertContained( "action001", actions.toString() );
			Assert.assertContained( "action002", actions.toString() );
			Assert.assertContained( "action003", actions.toString() );
			
			
			actions = testSubject.getOutgoingActionsForState( statename002 );
			Assert.assertEquals( actions.length, 0 );
		}
		
		
	}
}